package com.db.stexchem.client.gui;

import java.awt.Color;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import com.db.stexchem.client.Client;
import com.db.stexchem.exceptions.BadRequestException;
import com.db.stexchem.message.Operation;
import com.db.stexchem.message.Order;
import com.db.stexchem.message.OrderType;

public class OrderEntryPanel extends JPanel {
  private boolean stockEntered = false;
  private boolean quantityEntered = false;
  private boolean priceEntered = false;
  
  private JTextField stockTextField = new JTextField();
  private IntegerNumberTextField quantityTextField = new IntegerNumberTextField();
  
  private JComboBox operationComboBox = new JComboBox(Operation.values());
  private JComboBox typeComboBox = new JComboBox(OrderType.values());
  
  private DoubleNumberTextField priceTextField = new DoubleNumberTextField();
  
  private JLabel priceLabel = new JLabel("Price");
  
  private JLabel messageLabel = new JLabel(" ");
  private JButton submitButton = new JButton("Submit");
  
  private OrderTableModel orderTableModel = null;
  private transient Client application = null;
  
  private GridBagConstraints constraints = new GridBagConstraints();

  public OrderEntryPanel(final OrderTableModel orderTableModel,
      final Client application) {
    setName("OrderEntryPanel");
    this.orderTableModel = orderTableModel;
    this.application = application;

    SubmitActivator activator = new SubmitActivator();
    stockTextField.addKeyListener(activator);
    quantityTextField.addKeyListener(activator);
    priceTextField.addKeyListener(activator);

    setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
    setLayout(new GridBagLayout());
    createComponents();
  }

  public void addActionListener(ActionListener listener) {
    submitButton.addActionListener(listener);
  }

  public void setMessage(String message) {
    messageLabel.setText(message);
    if (message == null || message.equals(""))
      messageLabel.setText(" ");
  }

  public void clearMessage() {
    setMessage(null);
  }

  private void createComponents() {
    constraints.fill = GridBagConstraints.BOTH;
    constraints.weightx = 1;

    int x = 0;
    int y = 0;

    add(new JLabel("Stock"), x, y);
    add(new JLabel("Quantity"), ++x, y);
    add(new JLabel("Side"), ++x, y);
    add(new JLabel("Type"), ++x, y);
    constraints.ipadx = 30;
    add(priceLabel, ++x, y);
    
    constraints.ipadx = 0;
 
    constraints.ipadx = 30;

    stockTextField.setName("stockTextField");
    add(stockTextField, x = 0, ++y);
    constraints.ipadx = 0;
    quantityTextField.setName("QuantityTextField");
    add(quantityTextField, ++x, y);
    operationComboBox.setName("operationComboBox");
    add(operationComboBox, ++x, y);
    typeComboBox.setName("TypeComboBox");
    add(typeComboBox, ++x, y);
    priceTextField.setName("priceTextField");
    add(priceTextField, ++x, y);

    constraints.insets = new Insets(3, 0, 0, 0);
    constraints.gridwidth = GridBagConstraints.RELATIVE;

    constraints.gridwidth = GridBagConstraints.REMAINDER;
    submitButton.setName("SubmitButton");
    add(submitButton, x, ++y);
    constraints.gridwidth = 0;
    add(messageLabel, 0, ++y);

    typeComboBox.addItemListener(new PriceListener());

    Font font = new Font(messageLabel.getFont().getFontName(), Font.BOLD, 12);
    messageLabel.setFont(font);
    messageLabel.setForeground(Color.red);
    messageLabel.setHorizontalAlignment(JLabel.CENTER);
    submitButton.setEnabled(false);
    submitButton.addActionListener(new SubmitListener());
    activateSubmit();
  }

  private JComponent add(JComponent component, int x, int y) {
    constraints.gridx = x;
    constraints.gridy = y;
    add(component, constraints);
    return component;
  }

  private void activateSubmit() {
    OrderType type = (OrderType) typeComboBox.getSelectedItem();
    boolean activate = stockEntered && quantityEntered;

    if (type == OrderType.MARKET)
      submitButton.setEnabled(activate);
    else if (type == OrderType.LIMIT)
      submitButton.setEnabled(activate && priceEntered);
  }

  private class PriceListener implements ItemListener {
    public void itemStateChanged(ItemEvent e) {
      OrderType item = (OrderType) typeComboBox.getSelectedItem();
      if (item == OrderType.MARKET) {
        enableLimitPrice(false);
      } else if (item == OrderType.LIMIT) {
        enableLimitPrice(true);
      } else {
        enableLimitPrice(true);
      }
      activateSubmit();
    }

    private void enableLimitPrice(boolean enabled) {
      Color labelColor = enabled ? Color.black : Color.gray;
      Color bgColor = enabled ? Color.white : Color.gray;
      priceTextField.setEnabled(enabled);
      priceTextField.setBackground(bgColor);
      priceLabel.setForeground(labelColor);
    }

  }

  private class SubmitListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      Order order = new Order();
      order.setStockName(stockTextField.getText());
      order.setOperation((Operation) operationComboBox.getSelectedItem());
      order.setOrderType((OrderType) typeComboBox.getSelectedItem());
      order.setNShares(Integer.valueOf(quantityTextField.getText()));

      OrderType type = order.getOrderType();
      if (type == OrderType.LIMIT)
        order.setPrice(Float.valueOf(priceTextField.getText()));

      int orderNo;
      try {
        orderNo = application.placeOrder(order);
      } catch (IllegalStateException | IllegalArgumentException | IOException
          | BadRequestException e1) {
        JOptionPane.showMessageDialog(OrderEntryPanel.this, e1.getMessage(),
            "Place order error", JOptionPane.ERROR_MESSAGE);
        return;
      }
      order.setOrderNo(orderNo);
      orderTableModel.addOrder(order);

    }
  }

  private class SubmitActivator implements KeyListener, ItemListener {
    public void keyReleased(KeyEvent e) {
      Object obj = e.getSource();
      if (obj == stockTextField) {
        stockEntered = testField(obj);
      } else if (obj == quantityTextField) {
        quantityEntered = testField(obj);
      } else if (obj == priceTextField) {
        priceEntered = testField(obj);
      }
      activateSubmit();
    }

    public void itemStateChanged(ItemEvent e) {
      activateSubmit();
    }

    private boolean testField(Object o) {
      String value = ((JTextField) o).getText();
      value = value.trim();
      return value.length() > 0;
    }

    public void keyTyped(KeyEvent e) {
    }

    public void keyPressed(KeyEvent e) {
    }
  }
}
